package com.bytz.modules.cms.user.service.impl;

import cn.hutool.core.bean.copier.BeanCopier;
import cn.hutool.core.bean.copier.CopyOptions;
import com.boya.cup.flowable.service.model.response.*;
import com.boya.cup.flowable.service.model.response.auditpage.AuditPageModel;
import com.bytz.common.api.vo.Result;
import com.bytz.common.entity.IFlowEntity;
import com.bytz.common.system.vo.LoginUser;
import com.bytz.common.util.SecurityUtils;
import com.bytz.modules.bpm.client.model.*;
import com.bytz.modules.bpm.client.service.IFlowProcBizPartService;
import com.bytz.modules.bpm.client.service.impl.*;
import com.bytz.modules.bpm.client.util.GetAuditPageInfoUtil;
import com.bytz.modules.cms.order.constant.OrderConstants;
import com.bytz.modules.cms.order.constants.OrderFlowConstants;
import com.bytz.modules.cms.order.entity.Order;
import com.bytz.modules.cms.order.service.IOrderService;
import com.bytz.modules.cms.user.entity.EcAudit;
import com.bytz.modules.cms.user.model.EcAuditEntity;
import com.bytz.modules.cms.user.model.EcAuditSaveRo;
import com.bytz.modules.cms.user.service.IEcAuditFlowService;
import com.bytz.modules.cms.user.service.IEcAuditService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @program: cms-backend
 * @description:
 * @author: KyleWang
 * @create: 2022-10-31 16:56
 **/
@Service
@Slf4j
public class EcAuditFlowServiceImpl extends BizFlowServiceCommonImpl<EcAudit, EcAuditSaveRo, EcAuditEntity, IEcAuditService, IFlowProcBizPartService> implements IEcAuditFlowService {

    @Autowired
    IOrderService orderService;


    @Override
    public BizFlowProperty getFlowProperty() {
        return OrderFlowConstants.EcFlowProperty.EC_PROPERTY;
    }

    @Override
    protected void setFlowProcBizPartBehavior() {
        //就一个节点，不需要记录part数据
        this.flowProcBizPartBehavior = new DefaultFlowProcBizPartBehavior(this, this.flowProcBizPartService) {
            @Override
            public void ensureAssigneeIsParticipant(String assignee, String businessKey) {
            }

            @Override
            public void updateProcBizParts(List<String> userIds, String businessKey) {
            }
        };
    }

    @Override
    protected void setCompleteProcessBehavior() {
        this.completeProcessBehavior = new DefaultCompleteProcessBehavior(this) {
            @Override
            public void setCompleteProcessStatus(IFlowEntity entity) throws Exception {
                super.setCompleteProcessStatus(entity);
                EcAudit ecAudit = toDbEntity(entity);
                String status = ecAudit.getStatus();
                orderService.lambdaUpdate()
                        .eq(Order::getId, ecAudit.getOrderId())
                        .set(Order::getEcStatus, status)
                        .update();
            }
        };
    }

    @Override
    protected void setRejectTaskBehavior() {
        this.rejectTaskBehavior = new DefaultRejectTaskBehavior(this) {

            @Override
            public IFlowEntity beforeReject(AuditEntityBase auditEntity, IFlowEntity entity) throws Exception {
                EcAudit ecAudit = toDbEntity(entity);
                if (!StringUtils.equals(ecAudit.getStatus(), OrderConstants.EcStatus.APPROVING)) {
                    throw new UnsupportedOperationException("流程状态错误");
                }

                return super.beforeReject(auditEntity, ecAudit);
            }


            @Override
            public boolean setRejectTaskStatus(TaskRejectResponse rejectResponse, AuditEntityBase auditEntity, IFlowEntity entity) {
                boolean result = super.setRejectTaskStatus(rejectResponse, auditEntity, entity);
                EcAudit ecAudit = toDbEntity(entity);
                String status = entity.getStatus();
                //更新退回状态和退回信息
                orderService.lambdaUpdate()
                        .eq(Order::getId, ecAudit.getOrderId())
                        .set(Order::getEcStatus, status)
                        .set(Order::getEcRejectOpinion, auditEntity.getOpinion())
                        .update();
                return result;
            }
        };
    }

    @Override
    protected void setStartProcessBehavior() {
        this.startProcessBehavior = new DefaultStartProcessBehavior(this) {

            @Override
            public IFlowEntity beforeStartProcess(IFlowSaveEntity saveEntity, StartProcessParam startProcessParam) throws Exception {
                return super.beforeStartProcess(saveEntity, startProcessParam);
            }

            @Override
            public void afterStartProcess(IFlowEntity entity, ProcessInstanceModel pim) throws Exception {
                super.afterStartProcess(entity, pim);
                AuditEntityBase auditEntityBase = new AuditEntityBase();
                auditEntityBase.setProcInstId(pim.getProcessInstanceId());
                auditEntityBase.setBizId(pim.getBusinessKey());
                CompleteTaskResponse copy = BeanCopier.create(pim, new CompleteTaskResponse(), CopyOptions.create().ignoreNullValue()).copy();
                completeTaskBehavior.afterDoCompleteTask(copy, auditEntityBase, entity);

            }

            @Override
            public String getBusinessName(IFlowEntity entity) {
                EcAudit ecAudit = toDbEntity(entity);
                Order order = orderService.getById(ecAudit.getOrderId());

                return Stream.of(order.getContractNumber(), order.getProjectName(), "EC流程").filter(StringUtils::isNotBlank).collect(Collectors.joining(":"));

            }
        };
    }

    @Override
    @Transactional(
            propagation = Propagation.REQUIRED,
            rollbackFor = {Exception.class}
    )
    public void doReject(EcAuditEntity auditEntity, IFlowEntity entity) throws Exception {
        entity = this.rejectTaskBehavior.beforeReject(auditEntity, entity);

        // 模拟退回响应
        LoginUser loginUser = SecurityUtils.getLoginUser();
        TaskRejectResponse taskRejectResponse = new TaskRejectResponse();
        List<IdentityLink> identityLinks = new ArrayList<>();
        IdentityLink identityLink = new IdentityLink();
        identityLinks.add(identityLink);
        identityLink.setAssignee(loginUser.getId());
        identityLink.setAssigneeName(loginUser.getRealname());
        identityLink.setStartTime(new Date());
        identityLink.setTaskId(auditEntity.getTaskId());
        identityLink.setTaskName(auditEntity.getTaskName());
        taskRejectResponse.setIdentityLinks(identityLinks);

        this.rejectTaskBehavior.afterReject(taskRejectResponse, auditEntity, entity);
    }

    @Override
    @Transactional(
            propagation = Propagation.REQUIRES_NEW,
            rollbackFor = {Exception.class}
    )
    public boolean terminate(String orderId, String reason) throws Exception {
        Optional<EcAudit> ecAuditOpt = this.crudService.queryByOrderId(orderId);
        if (ecAuditOpt.isPresent()) {
            EcAudit ecAudit = ecAuditOpt.get();
            if (StringUtils.isBlank(ecAudit.getProcInstId()) && ecAudit.getCompleteTime() != null) {
                log.info("ec流程id:{}尚未开始或已完成", ecAudit.getId());
                return false;
            }
            EcAuditEntity ecAuditEntity = new EcAuditEntity();
            ecAuditEntity.setBizId(ecAudit.getId());
            ecAuditEntity.setProcInstId(ecAudit.getProcInstId());
            ecAuditEntity.setTerminateProcessReason(reason);
            this.doTerminateProcessInstance(ecAuditEntity, ecAudit);
            return true;
        } else {
            log.info("找不到ec流程，orderId：{}", orderId);
            return false;
        }
    }
}